package com.example.mykotlin.controller

import cn.dev33.satoken.annotation.SaCheckPermission
import com.example.mykotlin.base.result.PageParam
import com.example.mykotlin.base.result.ServiceException
import com.example.mykotlin.base.util.Audit
import com.example.mykotlin.base.util.except
import com.example.mykotlin.base.util.runService
import com.example.mykotlin.base.util.selectById
import com.example.mykotlin.base.util.tryOnly
import com.example.mykotlin.mapper.UserPermissionMapper
import com.example.mykotlin.mapper.UserRoleMapper
import com.example.mykotlin.model.dto.InsertUserPermissionsDTO
import com.example.mykotlin.model.dto.InsertUserRolesDTO
import com.example.mykotlin.model.entity.ApiPermission
import com.example.mykotlin.model.entity.Role
import com.example.mykotlin.model.entity.User
import com.example.mykotlin.model.entity.UserPermission
import com.example.mykotlin.model.entity.UserRole
import com.example.mykotlin.model.enums.SystemRole
import com.mybatisflex.kotlin.extensions.condition.allAnd
import com.mybatisflex.kotlin.extensions.condition.and
import com.mybatisflex.kotlin.extensions.db.deleteWith
import com.mybatisflex.kotlin.extensions.db.filter
import com.mybatisflex.kotlin.extensions.db.mapper
import com.mybatisflex.kotlin.extensions.db.paginate
import com.mybatisflex.kotlin.extensions.db.update
import com.mybatisflex.kotlin.extensions.kproperty.eq
import com.mybatisflex.kotlin.extensions.kproperty.`in`
import com.mybatisflex.kotlin.extensions.vec.vecOf
import com.mybatisflex.kotlin.extensions.wrapper.andAll
import com.mybatisflex.kotlin.extensions.wrapper.whereWith
import com.mybatisflex.kotlin.vec.count
import io.swagger.v3.oas.annotations.Operation
import io.swagger.v3.oas.annotations.Parameter
import io.swagger.v3.oas.annotations.tags.Tag
import jakarta.validation.constraints.Min
import org.apache.commons.lang3.StringUtils
import org.springframework.validation.annotation.Validated
import org.springframework.web.bind.annotation.GetMapping
import org.springframework.web.bind.annotation.PostMapping
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestParam
import org.springframework.web.bind.annotation.RestController
import com.mybatisflex.kotlin.vec.filter as atCondition

@Tag(name = "用户信息表Controller", description = "相关接口")
@RestController
@Validated
@RequestMapping("/user")
class UserController {
    @GetMapping
    @Operation(summary = "根据主键查询用户信息", description = "返回用户信息User对象")
    @SaCheckPermission("GET_user")
    fun getUserById(
        @RequestParam @Parameter(description = "用户信息表主键") @Min(
            value = 1,
            message = "主键不能小于1"
        ) id: Long
    ) =
        runService { selectById<User>(id) }

    @GetMapping("/inPage")
    @Operation(summary = "分页条件查询用户信息", description = "返回用户信息User对象列表")
    @SaCheckPermission("GET_user_inPage")
    fun getUserInPage(user: User, @Validated p: PageParam) = runService {
        paginate<User>(p.page()) {
            select(*except<User>(User::password))
            andAll(
                (User::id eq user.id).`when`(user.id != null),
                (User::username eq user.username).`when`(StringUtils.isNotEmpty(user.username)),
                (User::nickname eq user.nickname).`when`(StringUtils.isNotEmpty(user.nickname)),
                (User::phone eq user.phone).`when`(StringUtils.isNotEmpty(user.phone)),
            )
        }
    }

    @GetMapping("/username")
    @Operation(summary = "检验用户名唯一性", description = "返回用户名是否可用(ture:可用[不重复],false:不可用[重复了])")
    fun checkUserName(@RequestParam @Parameter(description = "用户名") username: String) = runService {
        vecOf<User>().atCondition { User::username eq username }.count() == 0L
    }

    @GetMapping("/nickname")
    @Operation(summary = "检验昵称唯一性", description = "返回昵称是否可用(ture:可用[不重复],false:不可用[重复了])")
    fun checkNickname(@RequestParam @Parameter(description = "昵称") nickname: String) = runService {
        vecOf<User>().atCondition { User::nickname eq nickname }.count() == 0L
    }

    @PostMapping("/permission")
    @Operation(summary = "直接给用户绑定多个权限", description = "直接给用户绑定多个权限")
    @SaCheckPermission("POST_user_permission")
    @Audit
    fun insertUserPermissions(@RequestBody userPermissions: InsertUserPermissionsDTO) = runService {
        selectById<User>(userPermissions.userId!!)
            ?: throw ServiceException("[userId=${userPermissions.userId}]数据不存在")
        if (!userPermissions.addPermissionList.isNullOrEmpty()) {
            val addPermissionExistList = filter<ApiPermission>(ApiPermission::id) {
                ApiPermission::id `in` userPermissions.addPermissionList!!
            }
            if (addPermissionExistList.isNotEmpty()) {
                val permissionList = addPermissionExistList.map { it.id ?: "" }
                // 查询数据库中已分配了的用户权限
                val userPermissionExistList = filter<UserPermission> {
                    allAnd(
                        UserPermission::userId eq userPermissions.userId,
                        UserPermission::permissionId `in` permissionList
                    )
                }
                val insertUserPermissionList: List<UserPermission>?
                var updateUserPermissionIdList: List<String>? = null
                // 数据库中已分配了的用户权限为空则全部绑定新增
                if (userPermissionExistList.isEmpty()) {
                    insertUserPermissionList = permissionList.map {
                        UserPermission(
                            userPermissions.userId, it, false
                        )
                    }
                } else {
                    // 数据库中已分配了部分要新插入的用户权限，区分新增和修改
                    // 新增的
                    insertUserPermissionList =
                        permissionList.minus(userPermissionExistList.map { it.permissionId }.toSet())
                            .map { UserPermission(userPermissions.userId, it, false) }
                    // 需要修改的
                    updateUserPermissionIdList = userPermissionExistList.map { it.permissionId ?: "" }
                }
                if (insertUserPermissionList.isNotEmpty())
                    tryOnly {
                        mapper<UserPermissionMapper>().insertBatch(insertUserPermissionList)
                    }
                if (!updateUserPermissionIdList.isNullOrEmpty()) {
                    tryOnly {
                        update<UserPermission> {
                            UserPermission::isExcluded set false
                            whereWith {
                                (UserPermission::userId eq userPermissions.userId) and (UserPermission::permissionId `in` updateUserPermissionIdList!!)
                            }
                        }
                    }
                }
            }
        }
        if (!userPermissions.excludedPermissionList.isNullOrEmpty()) {
            val excludedPermissionList = filter<ApiPermission>(ApiPermission::id) {
                ApiPermission::id `in` userPermissions.excludedPermissionList!!
            }
            if (excludedPermissionList.isNotEmpty()) {
                val permissionList = excludedPermissionList.map { it.id ?: "" }
                // 查询数据库中已分配了的用户权限
                val userPermissionExistList = filter<UserPermission> {
                    allAnd(
                        UserPermission::userId eq userPermissions.userId,
                        UserPermission::permissionId `in` permissionList
                    )
                }
                val insertUserPermissionList: List<UserPermission>?
                var updateUserPermissionIdList: List<String>? = null
                // 数据库中已分配了的用户权限为空则全部绑定新增
                if (userPermissionExistList.isEmpty()) {
                    insertUserPermissionList = permissionList.map {
                        UserPermission(
                            userPermissions.userId, it, true
                        )
                    }
                } else {
                    // 数据库中已分配了部分要新插入的用户权限，区分新增和修改
                    // 新增的
                    insertUserPermissionList =
                        permissionList.minus(userPermissionExistList.map { it.permissionId }.toSet())
                            .map { UserPermission(userPermissions.userId, it, true) }
                    // 需要修改的
                    updateUserPermissionIdList = userPermissionExistList.map { it.permissionId ?: "" }
                }
                if (insertUserPermissionList.isNotEmpty())
                    tryOnly {
                        mapper<UserPermissionMapper>().insertBatch(insertUserPermissionList)
                    }
                if (!updateUserPermissionIdList.isNullOrEmpty())
                    tryOnly {
                        update<UserPermission> {
                            (UserPermission::isExcluded set true)
                            whereWith {
                                (UserPermission::userId eq userPermissions.userId) and (UserPermission::permissionId `in` updateUserPermissionIdList!!)
                            }
                        }
                    }
            }
        }
        if (!userPermissions.removePermissionList.isNullOrEmpty()) {
            tryOnly {
                deleteWith<UserPermission> {
                    allAnd(
                        UserPermission::userId eq userPermissions.userId,
                        UserPermission::permissionId `in` userPermissions.removePermissionList!!
                    )
                }
            }
        }
        return@runService true
    }

    @PostMapping("/role")
    @Operation(summary = "给用户分配多个角色", description = "给用户分配多个角色")
    @SaCheckPermission("POST_user_role")
    @Audit
    fun insertUserRoles(@RequestBody userRoles: InsertUserRolesDTO) = runService {
        selectById<User>(userRoles.userId!!)
            ?: throw ServiceException("用户[${userRoles.userId}]不存在")
        if (!userRoles.addRoleList.isNullOrEmpty()) {
            val addRoleList = filter<Role>(Role::id) { Role::id `in` userRoles.addRoleList!! }
            if (addRoleList.isNotEmpty()) {
                val roleList = addRoleList.map { it.id ?: "" }
                val inDbList = filter<UserRole> {
                    allAnd(
                        UserRole::userId eq userRoles.userId, UserRole::roleId `in` roleList
                    )
                }
                if (inDbList.isEmpty()) {
                    tryOnly {
                        mapper<UserRoleMapper>().insertBatch(roleList.map {
                            UserRole(
                                userRoles.userId, it
                            )
                        })
                    }
                } else if (inDbList.size < roleList.size) {
                    val minus = roleList.minus(inDbList.map { it.roleId }.toSet())
                    tryOnly {
                        mapper<UserRoleMapper>().insertBatch(minus.map { UserRole(userRoles.userId, it) })
                    }
                }
            }
        }
        if (!userRoles.removeRoleList.isNullOrEmpty()) {
            val removeRoleSet = userRoles.removeRoleList!!.toHashSet()
            removeRoleSet.remove(SystemRole.USER.name)
            tryOnly {
                deleteWith<UserRole> {
                    allAnd(
                        UserRole::userId eq userRoles.userId, UserRole::roleId `in` removeRoleSet
                    )
                }
            }
        }
        return@runService true
    }

}